home *** CD-ROM | disk | FTP | other *** search
/ Macwelt 1 / Macwelt DVD 1.toast / Web-Publishing / HTML-Editoren / Alpha ƒ / Mode Examples / Ada-Example.ada next >
Encoding:
Text File  |  2000-10-30  |  21.5 KB  |  691 lines

  1. -- Ada-Example.ada
  2. -- 
  3. -- Included in the Alpha distribution as an example of the Ada mode
  4.  
  5. -- Source of original document:
  6. -- 
  7. -- http://gserver.grads.vt.edu/cgi.adb
  8.  
  9.  
  10. with Ada.Strings.Unbounded;  use  Ada.Strings.Unbounded;
  11.  
  12. package CGI is
  13. -- This package is an Ada 95 interface to the "Common Gateway Interface" (CGI).
  14. -- This package makes it easier to create Ada programs that can be
  15. -- invoked by World-Wide-Web HTTP servers using the standard CGI interface.
  16. -- CGI is rarely referred to by its full name, so the package name is short.
  17. -- General information on CGI is available at "http://hoohoo.ncsa.uiuc.edu/cgi/".
  18.  
  19. -- Developed by (C) David A. Wheeler (wheeler@ida.org) June 1995.
  20. -- This is version 1.0.
  21.  
  22. -- This was inspired by a perl binding by Steven E. Brenner at
  23. --   "http://www.bio.cam.ac.uk/web/form.html"
  24. -- and another perl binding by L. Stein at
  25. --   "http://www-genome.wi.mit.edu/ftp/pub/software/WWW/cgi_docs.html"
  26. -- A different method for interfacing binding Ada with CGI is to use the
  27. -- "Un-CGI" interface at "http://www.hyperion.com/~koreth/uncgi.html".
  28.  
  29. -- This package automatically loads information from CGI on program start-up.
  30. -- It loads information sent from "Get" or "Post" methods and automatically
  31. -- splits the data into a set of variables that can be accessed by position or
  32. -- by name.  An "Isindex" request is translated into a request with a single
  33. -- key named "isindex" with its Value as the query value.
  34.  
  35. -- This package provides two data access methods:
  36. -- 1) As an associative array; simply provide the key name and the
  37. --    value associated with that key will be returned.
  38. -- 2) As a sequence of key-value pairs, indexed from 1 to Argument_Count.
  39. --    This is similar to Ada library Ada.Command_Line.
  40. -- The main access routines support both String and Unbounded_String.
  41.  
  42. -- See the documentation file for more information and sample programs.
  43.  
  44. function Parsing_Errors return Boolean;  -- True if Error on Parse.
  45. function Input_Received return Boolean;  -- True if Input Received.
  46. function Is_Index       return Boolean;  -- True if an Isindex request made.
  47.   -- An "Isindex" request is turned into a Key of "isindex" at position 1,
  48.   -- with Value(1) as the actual query.
  49.  
  50. type CGI_Method_Type is (Get, Post, Unknown);
  51.  
  52. function CGI_Method return CGI_Method_Type;  -- True if Get_Method used.
  53.  
  54. -- Access data as an associative array - given a key, return its value.
  55. -- The Key value is case-sensitive.
  56. -- If a key is required but not present, raise Constraint_Error;
  57. -- otherwise a missing key's value is considered to be "".
  58. -- These routines find the Index'th value of that key (normally the first one).
  59. function Value(Key : in Unbounded_String; Index : in Positive := 1;
  60.                Required : in Boolean := False) return Unbounded_String;
  61. function Value(Key : in String; Index : in Positive := 1;
  62.                Required : in Boolean := False) return String;
  63. function Value(Key : in Unbounded_String; Index : in Positive := 1;
  64.               Required : in Boolean := False) return String;
  65. function Value(Key : in String; Index : in Positive := 1;
  66.                Required : in Boolean := False) return Unbounded_String;
  67.  
  68. -- Was a given key provided?
  69. function Key_Exists(Key : in String; Index : in Positive := 1) return Boolean;
  70. function Key_Exists(Key : in Unbounded_String; Index : in Positive := 1)
  71.          return Boolean;
  72.  
  73. -- How many of a given key were provided?
  74. function Key_Count(Key : in String) return Natural;
  75. function Key_Count(Key : in Unbounded_String) return Natural;
  76.  
  77.  
  78. -- Access data as an ordered list (it was sent as Key=Value);
  79. -- Keys and Values may be retrieved from Position (1 .. Argument_Count).
  80. -- Constraint_Error will be raised if (Position < 1 or Position > Argument_Count)
  81. function Argument_Count return Natural;          -- 0 means no data sent.
  82. function Key(Position : in Positive) return Unbounded_String;
  83. function Key(Position : in Positive) return String;
  84. function Value(Position : in Positive) return Unbounded_String;
  85. function Value(Position : in Positive) return String;
  86.  
  87. -- The following are helpful subprograms to simplify use of CGI.
  88.  
  89. function My_URL return String; -- Returns the URL of this script.
  90.  
  91. procedure Put_CGI_Header(Header : in String := "Content-type: text/html");
  92. -- Put CGI Header to Current_Output, followed by two carriage returns.
  93. -- This header determines what the program's reply type is.
  94. -- Default is to return a generated HTML document.
  95.  
  96. procedure Put_HTML_Head(Title : in String; Mail_To : in String := "");
  97. -- Puts to Current_Output an HTML header with title "Title".  This is:
  98. --   <HTML><HEAD><TITLE> _Title_ </TITLE>
  99. --   <LINK REV="made" HREF="mailto:  _Mail_To_ ">
  100. --   </HEAD><BODY>
  101. -- If Mail_To is omitted, the "made" reverse link is omitted.
  102.  
  103. procedure Put_HTML_Heading(Title : in String; Level : in Positive);
  104. -- Put an HTML heading at the given level with the given text.
  105. -- If level=1, this puts:  <H1>Title</H1>.
  106.  
  107. procedure Put_HTML_Tail;
  108. -- This is called at the end of an HTML document. It puts to Current_Output:
  109. --   </BODY></HTML>
  110.  
  111. procedure Put_Error_Message(Message : in String);
  112. -- Put to Current_Output an error message.
  113. -- This Puts an HTML_Head, an HTML_Heading, and an HTML_Tail.
  114. -- Call "Put_CGI_Header" before calling this.
  115.  
  116. procedure Put_Variables;
  117. -- Put to Current_Output all of the CGI variables as an HTML-formatted String.
  118.  
  119. function Line_Count (Value : in String) return Natural;
  120. -- Given a value that may have multiple lines, count the lines.
  121. -- Returns 0 if Value is the empty/null string (i.e., length=0)
  122.  
  123. function Line_Count_of_Value (Key : String) return Natural;
  124. -- Given a Key which has a Value that may have multiple lines,
  125. -- count the lines.  Returns 0 if Key's Value is the empty/null
  126. -- string (i.e., length=0) or if there's no such Key.
  127. -- This is the same as Line_Count(Value(Key)).
  128.  
  129. function Line (Value : in String; Position : in Positive)
  130.                return String;
  131. -- Given a value that may have multiple lines, return the given line.
  132. -- If there's no such line, raise Constraint_Error.
  133.  
  134. function Value_of_Line (Key : String; Position : Positive)
  135.                         return String;
  136. -- Given a Key which has a Value that may have multiple lines,
  137. -- return the given line.  If there's no such line, raise Constraint_Error.
  138. -- If there's no such Key, return the null string.
  139. -- This is the same as Line(Value(Key), Position).
  140.  
  141. function Get_Environment(Variable : in String) return String;
  142. -- Return the given environment variable's value.
  143. -- Returns "" if the variable does not exist.
  144.  
  145. end CGI;
  146.  
  147.  
  148.  
  149.  
  150. with Ada.Strings.Maps, Ada.Characters.Handling, Interfaces.C.Strings, Text_IO;
  151. use  Ada.Strings.Maps, Ada.Characters.Handling, Interfaces.C.Strings, Text_IO;
  152.  
  153. package body CGI is
  154. -- This package is an Ada 95 interface to the "Common Gateway Interface" (CGI).
  155. -- This package makes it easier to create Ada programs that can be
  156. -- invoked by HTTP servers using CGI.
  157.  
  158. -- Developed by David A. Wheeler, wheeler@ida.org, (C) June 1995.
  159.  
  160.  
  161. -- The following are key types and constants.
  162.  
  163. type Key_Value_Pair is record
  164.    Key, Value : Unbounded_String;
  165.    end record;
  166.  
  167. type Key_Value_Sequence is array(Positive range <>) of Key_Value_Pair;
  168. type Access_Key_Value_Sequence is access Key_Value_Sequence;
  169.  
  170.  
  171. Ampersands :    constant Character_Set      := To_Set('&');
  172. Equals     :    constant Character_Set      := To_Set('=');
  173. Plus_To_Space : constant Character_Mapping  := To_Mapping("+", " ");
  174.  
  175.  
  176.  
  177. -- The following are data internal to this package.
  178.  
  179. Parsing_Errors_Occurred : Boolean := True;
  180. Is_Index_Request_Made   : Boolean := False; -- Isindex request made?
  181.  
  182. CGI_Data : Access_Key_Value_Sequence; -- Initially nil.
  183.  
  184. Actual_CGI_Method : CGI_Method_Type := Get;
  185.  
  186.  
  187. -- The following are private "Helper" subprograms.
  188.  
  189. function Value_Without_Exception(S : chars_ptr) return String is
  190. -- Translate S from a C-style char* into an Ada String.
  191. -- If S is Null_Ptr, return "", don't raise an exception.
  192. begin
  193.   if S = Null_Ptr then return "";
  194.   else return Value(S);
  195.   end if;
  196. end Value_Without_Exception;
  197. pragma Inline(Value_Without_Exception);
  198.  
  199.  
  200. function Image(N : Natural) return String is
  201. -- Convert Positive N to a string representation.  This is just like
  202. -- Ada 'Image, but it doesn't put a space in front of it.
  203.  Result : String := Natural'Image(N);
  204. begin
  205.  return Result( 2 .. Result'Length);
  206. end Image;
  207.  
  208.  
  209. function Field_End(Data: Unbounded_String; Field_Separator: Character;
  210.                Starting_At : Positive := 1) return Natural is
  211. -- Return the end-of-field position in Data after "Starting_Index",
  212. -- assuming that fields are separated by the Field_Separator.
  213. -- If there's no Field_Separator, return the end of the Data.
  214. begin
  215.   for I in Starting_At .. Length(Data) loop
  216.     if Element(Data, I) = Field_Separator then return I-1; end if;
  217.   end loop; 
  218.   return Length(Data);
  219. end Field_End;
  220.  
  221.  
  222. function Hex_Value(H : in String) return Natural is
  223.  -- Given hex string, return its Value as a Natural.
  224.  Value : Natural := 0;
  225. begin
  226.  for P in 1.. H'Length loop
  227.    Value := Value * 16;
  228.    if H(P) in '0' .. '9' then Value := Value + Character'Pos(H(P)) -
  229.                                                Character'Pos('0');
  230.    elsif H(P) in 'A' .. 'F' then Value := Value + Character'Pos(H(P)) -
  231.                                                Character'Pos('A') + 10;
  232.    elsif H(P) in 'a' .. 'f' then Value := Value + Character'Pos(H(P)) -
  233.                                                Character'Pos('a') + 10;
  234.    else raise Constraint_Error;
  235.    end if;
  236.  end loop;
  237.  return Value;
  238. end Hex_Value;
  239.  
  240.  
  241. procedure Decode(Data : in out Unbounded_String) is
  242.  I : Positive := 1;
  243. -- In the given string, convert pattern %HH into alphanumeric characters,
  244. -- where HH is a hex number. Since this encoding only permits values
  245. -- from %00 to %FF, there's no need to handle 16-bit characters.
  246. begin
  247.  while I <= Length(Data) - 2 loop
  248.    if Element(Data, I) = '%' and Is_Hexadecimal_Digit(Element(Data, I+1)) and
  249.       Is_Hexadecimal_Digit(Element(Data, I+2)) then
  250.        Replace_Element(Data, I, Character'Val(Hex_Value(Slice(Data, I+1, I+2))));
  251.        Delete(Data, I+1, I+2);
  252.    end if;
  253.    I := I + 1;
  254.  end loop;
  255. end Decode;
  256.  
  257.  
  258.  
  259.  
  260. -- The following are public subprograms.
  261.  
  262.  
  263. function Get_Environment(Variable : String) return String is
  264. -- Return the value of the given environment variable.
  265. -- If there's no such environment variable, return an empty string.
  266.  
  267.   function getenv(Variable : chars_ptr) return chars_ptr;
  268.   pragma Import(C, getenv);
  269.   -- getenv is a standard C library function; see K&R 2, 1988, page 253.
  270.   -- it returns a pointer to the first character; do NOT free its results.
  271.  
  272.   Variable_In_C_Format : chars_ptr := New_String(Variable);
  273.   Result_Ptr : chars_ptr := getenv(Variable_In_C_Format);
  274.   Result : String := Value_Without_Exception(Result_Ptr);
  275. begin
  276.  Free(Variable_In_C_Format);
  277.  return Result;
  278. end Get_Environment;
  279.  
  280.  
  281. function Parsing_Errors return Boolean is
  282. begin
  283.  return Parsing_Errors_Occurred;
  284. end Parsing_Errors;
  285.  
  286.  
  287. function Argument_Count return Natural is
  288. begin
  289.   if CGI_Data = null then return 0;
  290.   else                   return CGI_Data.all'Length;
  291.   end if;
  292. end Argument_Count;
  293.  
  294.  
  295. function Input_Received return Boolean is
  296.   -- True if Input Received.
  297. begin
  298.   return Argument_Count /= 0; -- Input received if nonzero data entries.
  299. end Input_Received;
  300.  
  301.  
  302. function CGI_Method return CGI_Method_Type is
  303.   -- Return Method used to send data.
  304. begin
  305.   return Actual_CGI_Method;
  306. end CGI_Method;
  307.  
  308.  
  309. function Is_Index return Boolean is
  310. begin
  311.   return Is_Index_Request_Made;
  312. end Is_Index;
  313.  
  314.  
  315. function Value(Key : in Unbounded_String; Index : in Positive := 1;
  316.                Required : in Boolean := False)
  317.          return Unbounded_String is
  318.  My_Index : Positive := 1;
  319. begin
  320.  for I in 1 .. Argument_Count loop
  321.    if CGI_Data.all(I).Key = Key then
  322.       if Index = My_Index then
  323.         return CGI_Data.all(I).Value;
  324.       else
  325.         My_Index := My_Index + 1;
  326.       end if;
  327.    end if;
  328.  end loop;
  329.  -- Didn't find the Key.
  330.  if Required then
  331.    raise Constraint_Error;
  332.  else
  333.    return To_Unbounded_String("");
  334.  end if;
  335. end Value;
  336.  
  337.  
  338. function Value(Key : in String; Index : in Positive := 1;
  339.                Required : in Boolean := False)
  340.          return String is
  341. begin
  342.   return To_String(Value(To_Unbounded_String(Key), Index, Required));
  343. end Value;
  344.  
  345.  
  346. function Value(Key : in String; Index : in Positive := 1;
  347.                Required : in Boolean := False)
  348.          return Unbounded_String is
  349. begin
  350.   return Value(To_Unbounded_String(Key), Index, Required);
  351. end Value;
  352.  
  353.  
  354. function Value(Key : in Unbounded_String; Index : in Positive := 1;
  355.                Required : in Boolean := False)
  356.          return String is
  357. begin
  358.   return To_String(Value(Key, Index, Required));
  359. end Value;
  360.  
  361.  
  362. function Key_Exists(Key : in Unbounded_String; Index : in Positive := 1)
  363.          return Boolean is
  364.  My_Index : Positive := 1;
  365. begin
  366.  for I in 1 .. Argument_Count loop
  367.    if CGI_Data.all(I).Key = Key then
  368.       if Index = My_Index then
  369.         return True;
  370.       else
  371.         My_Index := My_Index + 1;
  372.       end if;
  373.    end if;
  374.  end loop;
  375.  return False;
  376. end Key_Exists;
  377.  
  378. function Key_Exists(Key : in String; Index : in Positive := 1) return Boolean is
  379. begin
  380.  return Key_Exists(To_Unbounded_String(Key), Index);
  381. end Key_Exists;
  382.  
  383. function Key_Count(Key : in Unbounded_String) return Natural is
  384.  Count : Natural := 0;
  385. begin
  386.  for I in 1 .. Argument_Count loop
  387.    if CGI_Data.all(I).Key = Key then
  388.         Count := Count + 1;
  389.    end if;
  390.  end loop;
  391.  return Count;
  392. end Key_Count;
  393.  
  394. function Key_Count(Key : in String) return Natural is
  395. begin
  396.   return Key_Count(To_Unbounded_String(Key));
  397. end Key_Count;
  398.  
  399. function Key(Position : in Positive) return Unbounded_String is
  400. begin
  401.  return CGI_Data.all(Position).Key;
  402. end Key;
  403.  
  404.  
  405. function Key(Position : in Positive) return String is
  406. begin
  407.  return To_String(Key(Position));
  408. end Key;
  409.  
  410.  
  411. function Value(Position : in Positive) return Unbounded_String is
  412. begin
  413.  return CGI_Data.all(Position).Value;
  414. end Value;
  415.  
  416.  
  417. function Value(Position : in Positive) return String is
  418. begin
  419.  return To_String(Value(Position));
  420. end Value;
  421.  
  422.  
  423. function My_URL return String is
  424.  -- Returns the URL of this script.
  425. begin
  426.   return "http://" & Get_Environment("SERVER_NAME") &
  427.           Get_Environment("SCRIPT_NAME");
  428. end My_URL;
  429.  
  430.  
  431. procedure Put_CGI_Header(Header : in String := "Content-type: text/html") is
  432. -- Put Header to Current_Output, followed by two carriage returns.
  433. -- Default is to return a generated HTML document.
  434. begin
  435.   Put_Line(Header);
  436.   New_Line;
  437. end Put_CGI_Header;
  438.  
  439.  
  440. procedure Put_HTML_Head(Title : in String; Mail_To : in String := "") is
  441. begin
  442.   Put_Line("<HTML><HEAD><TITLE>" & Title & "</TITLE>");
  443.   if Mail_To /= "" then
  444.     Put_Line("<LINK REV=""made"" HREF=""mailto:" &  Mail_To  & """>");
  445.   end if;
  446.   Put_Line("</HEAD><BODY>");
  447. end Put_HTML_Head;
  448.  
  449.  
  450. procedure Put_HTML_Heading(Title : in String; Level : in Positive) is
  451. -- Put an HTML heading, such as <H1>Title</H1>
  452. begin
  453.   Put_Line("<H" & Image(Level) & ">" & Title & "</H" & Image(Level) & ">");
  454. end Put_HTML_Heading;
  455.  
  456.  
  457. procedure Put_HTML_Tail is
  458. begin
  459.   Put_Line("</BODY></HTML>");
  460. end Put_HTML_Tail;
  461.  
  462.  
  463. procedure Put_Error_Message(Message : in String) is
  464. -- Put to Current_Output an error message.
  465. begin
  466.   Put_HTML_Head("Fatal Error Encountered by Script " & My_URL);
  467.   Put_HTML_Heading("Fatal Error: " & Message, 1);
  468.   Put_HTML_Tail;
  469.   New_Line;
  470. end Put_Error_Message;
  471.  
  472.  
  473. procedure Put_Variables is
  474. -- Put to Current_Output all of the data as an HTML-formatted String.
  475. begin
  476.  for I in 1 .. Argument_Count loop
  477.    Put("<B>");
  478.    Put(To_String(CGI_Data.all(I).Key));
  479.    Put("</B> is <I>");
  480.    Put(To_String(CGI_Data.all(I).Value));
  481.    Put_Line("</I><BR>");
  482.  end loop;
  483. end Put_Variables;
  484.  
  485.  
  486.  
  487. -- Helper routine -
  488.  
  489. function Next_CRLF (S : in String; N : in Natural)
  490.          return Natural
  491. -- Return the location within the string of the next CRLF sequence
  492. -- beginning with the Nth character within the string S;
  493. -- return 0 if the next CRLF sequence is not in the string
  494. is
  495.    I : Natural := N;
  496. begin
  497.    while I < S'LAST loop
  498.       if S(I) = ASCII.CR  and then  S(I+1) = ASCII.LF then
  499.          return I;
  500.       else
  501.          I := I + 1;
  502.       end if;
  503.    end loop;
  504.    return 0;
  505. end;
  506.  
  507.  
  508.  
  509. function Line_Count (Value : in String) return Natural
  510. -- Count the number of lines inside the given string.
  511. -- returns 0 if Key_Value is the empty/null string,
  512. -- i.e., if its length is zero; otherwise, returns
  513. -- the number of "lines" in Key_Value, effectively
  514. -- returning the number of CRLF sequences + 1;
  515. -- for example, both "AB/CDEF//GHI" and "AB/CDEF//"
  516. -- (where / is CRLF) return Line_Count of 4.
  517. is
  518.    Number_of_Lines : Natural := 0;
  519.    I : Natural := Value'FIRST;
  520. begin
  521.    if Value'LENGTH = 0 then
  522.       return 0;
  523.    else
  524.       loop
  525.          I := Next_CRLF (Value, I+1);
  526.       exit when I = 0;
  527.          Number_of_Lines := Number_of_Lines + 1;
  528.       end loop;
  529.       -- Always count the line (either non-null or null) after
  530.       -- the last CRLF as a line
  531.       Number_of_Lines := Number_of_Lines + 1;
  532.       return Number_of_Lines;
  533.    end if;
  534. end;
  535.  
  536.  
  537. function Line (Value : in String; Position : in Positive)
  538.                return String
  539. -- Return the given line position value.
  540. -- that is separated by the n-1 and the nth CRLF sequence
  541. -- or if there is no nth CRLF sequence, then returns the line
  542. -- delimited by the n-1 CRLF and the end of the string
  543.  
  544. is
  545.    Next : Natural := 1;
  546.    Line_Number : Natural := 0;
  547.    Start_of_Line, End_of_Line : Natural;
  548. begin
  549.    End_of_Line := Next_CRLF (Value, 1);
  550.    if End_of_Line = 0 then
  551.       -- no CRLF sequence on the "line"
  552.       if Position > 1 then
  553.          -- raise an exception if requesting > 1
  554.          raise Constraint_Error;
  555.       else
  556.          -- otherwise, requesting first line
  557.          -- return original string, even if null string
  558.          return Value;
  559.       end if;
  560.    else
  561.       -- There's at least one CRLF on the "line"
  562.       for I in 1..Position loop
  563.          Start_of_Line := Next;
  564.          End_of_Line := Next_CRLF (Value, Next);
  565.          -- normally, the line is Start_of_Line .. End_of_Line-1
  566.          -- if no more CRLFs on line, it's Start_of_Line .. 'LAST
  567.          exit when End_of_Line = 0;
  568.          Line_Number := Line_Number + 1;
  569.          -- skip past the 2 chars, CRLF, to start next search
  570.          Next := End_of_Line + 2;
  571.       end loop;
  572.       -- if we fall out of loop normally, End_of_Line is non-zero
  573.       if End_of_Line > 0 then
  574.          -- and Position had better be equal to Line_Number
  575.          if Position = Line_Number then
  576.             return Value (Start_of_Line .. End_of_Line-1);
  577.          else
  578.             raise Constraint_Error;
  579.          end if;
  580.       else
  581.          -- we exit the loop prematurely because there's not
  582.          -- enough CRLFs in the line,
  583.          -- thus Line_Number is one less than Position
  584.          if Position = Line_Number+1 then
  585.             return Value (Start_of_Line .. Value'LAST);
  586.          else
  587.             raise Constraint_Error;
  588.          end if;
  589.       end if;
  590.  end if;
  591. end Line;
  592.  
  593.  
  594. function Line_Count_of_Value (Key : String) return Natural is
  595. begin
  596.    if Key_Exists (Key) then
  597.       return Line_Count (Value(Key));
  598.    else
  599.       return 0;
  600.    end if;
  601. end Line_Count_of_Value;
  602.  
  603.  
  604. function Value_of_Line (Key : String; Position : Positive) return String is
  605. begin
  606.    if Key_Exists (Key) then
  607.       return Line (Value(Key), Position);
  608.    else
  609.       return "";
  610.    end if;
  611. end Value_of_Line;
  612.  
  613.  
  614.  
  615. -- Initialization routines, including some private procedures only
  616. -- used during initialization.
  617.  
  618. procedure Set_CGI_Position(Key_Number : in Positive;
  619.                            Datum : in Unbounded_String) is
  620.   Last : Natural := Field_End(Datum, '=');
  621. -- Given a Key number and a datum of the form key=value
  622. -- assign the CGI_Data(Key_Number) the values of key and value.
  623. begin
  624.   CGI_Data.all(Key_Number).Key   := To_Unbounded_String(Slice(Datum, 1, Last));
  625.   CGI_Data.all(Key_Number).Value := To_Unbounded_String(Slice(Datum,
  626.                                                       Last+2, Length(Datum)));
  627.   Decode(CGI_Data.all(Key_Number).Key);
  628.   Decode(CGI_Data.all(Key_Number).Value);
  629. end Set_CGI_Position;
  630.  
  631.  
  632. procedure Set_CGI_Data(Raw_Data : in Unbounded_String) is
  633. -- Set CGI_Data using Raw_Data.
  634.   Key_Number : Positive := 1;
  635.   Character_Position : Positive := 1;
  636.   Last : Natural;
  637. begin
  638.  while Character_Position <= Length(Raw_Data) loop
  639.    Last := Field_End(Raw_Data, '&', Character_Position);
  640.    Set_CGI_Position(Key_Number, To_Unbounded_String(
  641.                        Slice(Raw_Data, Character_Position, Last)));
  642.    Character_Position := Last + 2; -- Skip over field separator.
  643.    Key_Number := Key_Number + 1;
  644.  end loop;
  645. end Set_CGI_Data;
  646.  
  647.  
  648. procedure Initialize is
  649.   Raw_Data : Unbounded_String;  -- Initially an empty string (LRM A.4.5(73))
  650.   Request_Method_Text : String := To_Upper(Get_Environment("REQUEST_METHOD"));
  651.   -- Initialize this package, most importantly the CGI_Data variable.
  652. begin
  653.  if Request_Method_Text = "GET" then
  654.     Actual_CGI_Method := Get;
  655.     Raw_Data := To_Unbounded_String(Get_Environment("QUERY_STRING"));
  656.  elsif Request_Method_Text = "POST" then
  657.     Actual_CGI_Method := Post;
  658.     declare
  659.       Raw_Data_String : String(1 ..
  660.                          Integer'Value(Get_Environment("CONTENT_LENGTH")));
  661.     begin
  662.       Get(Raw_Data_String);
  663.       Raw_Data := To_Unbounded_String(Raw_Data_String);
  664.     end;
  665.  else
  666.     Actual_CGI_Method := Unknown;
  667.  end if;
  668.  
  669.  Translate(Raw_Data, Mapping => Plus_To_Space); -- Convert "+"s to spaces.
  670.  
  671.  if Length(Raw_Data) > 0 then
  672.    if Index(Raw_Data, Equals) = 0 then
  673.      -- No "=" found, so this is an "Isindex" request.
  674.      Is_Index_Request_Made := True;
  675.      Raw_Data := "isindex=" & Raw_Data;
  676.    end if;
  677.    CGI_Data := new Key_Value_Sequence(1 .. 
  678.                    Ada.Strings.Unbounded.Count(Raw_Data, Ampersands)+1);
  679.    Set_CGI_Data(Raw_Data); 
  680.    Parsing_Errors_Occurred := False;
  681.  end if;
  682.  
  683. end Initialize;
  684.  
  685.  
  686. -- This library automatically parses CGI input on program start.
  687. begin
  688.   Initialize;
  689. end CGI;
  690.  
  691.